﻿Namespace Framework
    Public Class StickyComponentCollection(Of T As IStickyComponent)
        Inherits System.Collections.ObjectModel.ObservableCollection(Of T)
        Implements IStickyComponent

        Private _AttachedTo As DependencyObject
        Private _Dictionary As New Dictionary(Of String, T)

        Public Sub New()
            MyBase.New()
        End Sub
        Public Sub New(ByVal list As System.Collections.Generic.List(Of T))
            MyBase.New(list)
        End Sub
        Public Sub New(ByVal collection As System.Collections.Generic.IEnumerable(Of T))
            MyBase.New(collection)
        End Sub

        Protected Overrides Sub ClearItems()
            For Each c As IStickyComponent In Me
                StickyComponentManager.Detach(_AttachedTo, c)
            Next
            _Dictionary.Clear()
            MyBase.ClearItems()
        End Sub

        Public Shared Function GetKeyForItem(ByVal item As T) As String
            Dim result As String = Nothing
            If GetType(INamedStickyComponent).IsAssignableFrom(GetType(T)) Then
                result = DirectCast(item, INamedStickyComponent).Name
            End If
            Return result
        End Function

        Protected Overrides Sub InsertItem(ByVal index As Integer, ByVal item As T)
            If _AttachedTo IsNot Nothing Then
                StickyComponentManager.Attach(_AttachedTo, item)
            End If
            MyBase.InsertItem(index, item)
            Dim key As String = GetKeyForItem(item)
            If key IsNot Nothing Then
                _Dictionary.Add(key, item)
            End If
        End Sub

        Protected Overrides Sub RemoveItem(ByVal index As Integer)
            Dim c As IStickyComponent = Me.Item(index)
            If _AttachedTo IsNot Nothing Then
                StickyComponentManager.Detach(_AttachedTo, c)
            End If
            Dim key As String = GetKeyForItem(c)
            If key IsNot Nothing Then
                _Dictionary.Remove(key)
            End If
            MyBase.RemoveItem(index)
        End Sub

        Protected Overrides Sub SetItem(ByVal index As Integer, ByVal item As T)
            Dim old As IStickyComponent = Me.Item(index)
            If _AttachedTo IsNot Nothing Then
                StickyComponentManager.Detach(_AttachedTo, old)
                StickyComponentManager.Attach(_AttachedTo, item)
            End If
            MyBase.SetItem(index, item)

            Dim key As String = GetKeyForItem(old)
            If key IsNot Nothing Then
                _Dictionary.Remove(key)
            End If
            key = GetKeyForItem(item)
            If key IsNot Nothing Then
                _Dictionary.Add(key, item)
            End If
        End Sub

        Public ReadOnly Property Mode() As AttachMode Implements IStickyComponent.Mode
            Get
                Return AttachMode.Immediate
            End Get
        End Property

        Public Sub OnAttach(ByVal sender As Object, ByVal e As System.EventArgs) Implements IStickyComponent.OnAttach
            _AttachedTo = TryCast(sender, DependencyObject)
            If _AttachedTo IsNot Nothing Then
                For Each c As IStickyComponent In Me
                    StickyComponentManager.Attach(sender, c)
                Next
            End If
        End Sub

        Public Sub OnDetach(ByVal sender As Object, ByVal e As System.EventArgs) Implements IStickyComponent.OnDetach
            If _AttachedTo IsNot Nothing Then
                If (Not (TypeOf e Is RoutedEventArgs)) OrElse DirectCast(e, RoutedEventArgs).RoutedEvent IsNot FrameworkElement.UnloadedEvent Then
                    For Each c As IStickyComponent In Me
                        StickyComponentManager.Detach(sender, c)
                    Next
                End If
                _AttachedTo = Nothing
            End If
        End Sub

        Default Public Overloads Property Item(ByVal key As String) As T
            Get
                Return _Dictionary.Item(key)
            End Get
            Set(ByVal value As T)
                Dim item As T = _Dictionary.Item(key)
                Dim index As Integer = IndexOf(item)
                If index >= 0 Then
                    Me.Item(index) = value
                End If
            End Set
        End Property
    End Class
End Namespace